using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace Skywave.Windows.Forms
{
    public class ProgressInterface
    {
        public ProgressInterface(object descTarget, ProgressBar pb)
            : this(descTarget, "Text", "Visible", pb)
        {
        }
        public ProgressInterface(object descTarget, string descTargetTextProperty, string descTargetVisibleProperty, ProgressBar pb)
        {
            mDescTarget = descTarget;
            if (mDescTarget != null)
            {
                mDescTargetTextProperty = mDescTarget.GetType().GetProperty(descTargetTextProperty);
                if (mDescTargetTextProperty == null)
                {
                    throw new ArgumentException("The object specified as target does not have the property: '" + descTargetTextProperty + "'.");
                }
                mDescTargetVisibleProperty = mDescTarget.GetType().GetProperty(descTargetVisibleProperty);
                if (mDescTargetVisibleProperty == null)
                {
                    throw new ArgumentException("The object specified as target does not have the property: '" + descTargetVisibleProperty + "'.");
                }
                else
                {
                    if (!(mDescTargetVisibleProperty.PropertyType == typeof(bool)))
                    {
                        throw new ArgumentException("The target property: '" + descTargetVisibleProperty + "' should be of type: 'Boolean'.");
                    }
                }
            }
            mPB = pb;
        }

        private object mDescTarget;
        private System.Reflection.PropertyInfo mDescTargetTextProperty, mDescTargetVisibleProperty;
        public object Description
        {
            get
            {
                object res = null;
                if (mDescTarget != null && mDescTargetTextProperty != null)
                {
                    res = mDescTargetTextProperty.GetValue(mDescTarget, null);
                }
                return res;
            }
            set
            {
                if (mDescTarget != null && mDescTargetTextProperty != null)
                {
                    mDescTargetTextProperty.SetValue(mDescTarget, value, null);
                }
            }
        }

        private ProgressBar mPB;
        public ProgressBar PB
        {
            get { return mPB; }
            set { mPB = value; }
        }

        private ProgressInterface mParent;
        internal ProgressInterface Parent
        {
            get { return mParent; }
            set { mParent = value; }
        }

        private ProgressInterface mChild;
        internal ProgressInterface Child
        {
            get { return mChild; }
            set { mChild = value; }
        }

        internal void SetDescription(object desc)
        {
            //if (mDescription != null)
            Description = desc;
        }
        internal void SetValue(int value)
        {
            if (mPB != null)
                mPB.Value = value;
        }
        internal void AddValue(int value)
        {
            if (mPB != null)
            {
                if (mPB.Value + value <= mPB.Maximum)
                    mPB.Value += value;
                if (mParent != null) mParent.AddValue(value);
            }
        }
        internal void AddValue()
        {
            AddValue(1);
        }

        internal void ResetValue()
        {
            mPB.Value = mPB.Minimum;
        }

        internal void ResetAll()
        {
            Description = " ";
            mPB.Value = mPB.Minimum;
            mPB.Style = ProgressBarStyle.Continuous;
        }

        private int mPrevUserMaximum;
        private int PrevUserMaximum
        {
            get
            {
                return mPrevUserMaximum;
            }
        }

        private int mUserMaximum;
        private int UserMaximum
        {
            set
            {
                mPrevUserMaximum = mUserMaximum;
                //if (mPrevUserMaximum == 0) mPrevUserMaximum = value;
                mUserMaximum = value;
                if (mUserMaximum != mPrevUserMaximum)
                    FixMaximum();
            }
            get
            {
                return mUserMaximum;
            }
        }

        private void FixMaximum()
        {
            ProgressInterface pi = this;
            int pNewMax = 1;
            while (pi != null)
            {
                if (pi.UserMaximum != 0)
                    pNewMax *= pi.UserMaximum;
                pi = pi.Child;
            }
            int curMax = this.PB.Maximum;
            this.PB.Maximum = pNewMax;
            if (this.Parent != null)
            {
                FixParentTree(this.Parent);
            }
        }

        private void FixParentTree(ProgressInterface pi)
        {
            double loopRemain;
            if (pi._FixChildLoopCount == 0)
            {
                loopRemain = pi.UserMaximum;
                pi._FixChildLoopCount = pi.Child.UserMaximum;
            }
            else
            {
                loopRemain = ((double)(pi.PB.Maximum - pi.PB.Value) / pi._FixChildLoopCount);
                pi._FixChildLoopCount = pi.Child.PbLoopCount;
            }
            pi.PB.Maximum = pi.PB.Value + (int)(loopRemain * (double)pi.Child.PbLoopCount);

            if (pi.Parent != null)
            {
                FixParentTree(pi.Parent);
            }
        }

        internal void SetMaximum(int value)
        {
            if (mPB != null && value >= 0)
            {
                if (mChild == null)
                {
                    mPB.Maximum = value;
                }
                mPB.Value = mPB.Minimum;
                UserMaximum = value;
            }
        }

        private int PbLoopCount
        {
            get
            {
                return mPB.Maximum - mPB.Minimum;
            }
        }

        private int m_FixChildLoopCount;
        private int _FixChildLoopCount
        {
            set
            {
                m_FixChildLoopCount = value;
            }
            get
            {
                return m_FixChildLoopCount;
            }
        }

        internal void SetStyle(ProgressBarStyle progressBarStyle)
        {
            if (mPB != null)
                mPB.Style = progressBarStyle;
        }

        bool prevDescVisible, prevPbVisible;
        internal void StartEnforceVisibility()
        {
            if (mDescTarget != null && mDescTargetTextProperty != null && mDescTargetVisibleProperty != null)
            {
                prevDescVisible = (bool)mDescTargetVisibleProperty.GetValue(mDescTarget, null);
                prevPbVisible = mPB.Visible;

                mDescTargetVisibleProperty.SetValue(mDescTarget, true, null);
                mPB.Visible = true;
            }
        }

        internal void EndEnforceVisibility()
        {
            if (mDescTarget != null && mDescTargetTextProperty != null && mDescTargetVisibleProperty != null)
            {
                mDescTargetVisibleProperty.SetValue(mDescTarget, prevDescVisible, null);
                mPB.Visible = prevPbVisible;
            }
        }
    }
}
